﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PickGold
{
	/// <summary>
	/// 纤程包装类
	/// </summary>
	public class Fiber : ICollection<FiberTask>
	{
		class FiberEnumerator : IEnumerator, IComparer<FiberEnumerator>, IEqualityComparer<FiberEnumerator>
		{
			public FiberTask Task;
			public object Data;
			private IEnumerator _Enumerator;

			public object Current
			{
				get
				{
					if (this._Enumerator == null)
						this._Enumerator = this.Task(this.Data).GetEnumerator();
					return this._Enumerator.Current;
				}
			}

			public bool MoveNext()
			{
				if (this.Task == null)
					return false;

				if (this._Enumerator == null)
				{
					var e = this.Task(this.Data);
					if (e == null)
						return false;

					var t = e.GetType();
					if (!t.IsNestedPrivate)
						return false;

					if (t.DeclaringType != this.Task.Method.DeclaringType)
						return false;

					var o = typeof(object);
					if (o != t.BaseType)
						return false;

					if (t.Name.StartsWith(t.DeclaringType.Name))
						return false;

					if (t.Name.IndexOf(this.Task.Method.Name) < 0)
						return false;

					this._Enumerator = e.GetEnumerator();
				}
				if (this._Enumerator != null)
					return this._Enumerator.MoveNext();

				return false;
			}

			void IEnumerator.Reset()
			{
				this._Enumerator = this.Task(this.Data).GetEnumerator();
			}

			int IComparer<FiberEnumerator>.Compare(FiberEnumerator x, FiberEnumerator y)
			{
				if (x.Task == y.Task)
					return 0;

				return x.Task.GetHashCode().CompareTo(y.Task.GetHashCode());
			}

			bool IEqualityComparer<FiberEnumerator>.Equals(FiberEnumerator x, FiberEnumerator y)
			{
				if (x == null && y == null)
					return true;

				if (x == null || y == null)
					return false;

				if (x.Task == y.Task)
					return true;

				return false;
			}

			int IEqualityComparer<FiberEnumerator>.GetHashCode(FiberEnumerator obj)
			{
				if (obj == null || obj.Task == null)
					return 0;

				return obj.Task.GetHashCode();
			}
		}

		private Dictionary<FiberTask, FiberEnumerator> _Tasks;
		private FiberTask _Current;

		/// <summary>
		/// 构造一个纤程对象
		/// </summary>
		public Fiber()
		{
			this._Tasks = new Dictionary<FiberTask, FiberEnumerator>();
		}

		/// <summary>
		/// 构造一个纤程对象
		/// </summary>
		/// <param name="capacity">初始元素数</param>
		public Fiber(int capacity)
		{
			this._Tasks = new Dictionary<FiberTask, FiberEnumerator>(capacity);
		}

		/// <summary>
		/// 转移纤程
		/// </summary>
		public void Yield()
		{
			foreach (var item in this._Tasks)
			{
				try
				{
					if (this._Current != null)
					{
						if (this._Current == item.Key)
							this._Current = null;
						continue;
					}

					if (!item.Value.MoveNext())
					{
						this._Current = item.Key;
						this.Yield();
						this._Tasks.Remove(item.Key);
						break;
					}
				}
				catch
				{
					this._Current = item.Key;
					this.Yield();
					this._Tasks.Remove(item.Key);
					throw;
				}
			}
			this._Current = null;
		}

		/// <summary>
		/// 添加纤程任务
		/// </summary>
		/// <param name="argument">参数</param>
		/// <param name="item">纤程任务：【yield return ?】【yield break】</param>
		public void Yield(FiberTask item, object argument)
		{
			if (item != null)
				this._Tasks[item] = new FiberEnumerator { Task = item, Data = argument };
			else
				this.Yield();
		}

		void ICollection<FiberTask>.Add(FiberTask item)
		{
			this.Yield(item, null);
		}

		void ICollection<FiberTask>.Clear()
		{
			this._Tasks.Clear();
		}

		/// <summary>
		/// 是否存在指定任务
		/// </summary>
		/// <param name="item">指定的任务</param>
		/// <returns>是否存在</returns>
		public bool Contains(FiberTask item)
		{
			return this._Tasks.ContainsKey(item);
		}

		void ICollection<FiberTask>.CopyTo(FiberTask[] array, int arrayIndex)
		{
			this._Tasks.Keys.CopyTo(array, arrayIndex);
		}

		/// <summary>
		/// 当前任务总数
		/// </summary>
		public int Count
		{
			get
			{
				return this._Tasks.Count;
			}
		}

		bool ICollection<FiberTask>.IsReadOnly
		{
			get
			{
				return false;
			}
		}

		bool ICollection<FiberTask>.Remove(FiberTask item)
		{
			return this._Tasks.Remove(item);
		}

		/// <summary>
		/// 取枚举器
		/// </summary>
		/// <returns>枚举器</returns>
		public IEnumerator<FiberTask> GetEnumerator()
		{
			return this._Tasks.Keys.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}
	}

	/// <summary>
	/// 
	/// </summary>
	/// <param name="argument"></param>
	/// <returns></returns>
	public delegate IEnumerable FiberTask (object argument);
}
